﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using TireService.Data;
using DevExpress.Web.ASPxCallback;
using System.Configuration;
using DevExpress.Web.ASPxClasses;
using DevExpress.Web.ASPxGridView;

namespace TireService.Web.View.ServiceView
{
    public partial class CapacityPlanning : System.Web.UI.Page
    {
        private int _customerid;
        private int _taskid;
        private int _existingservicecarscheduledetailid;
        private int _selectedzipcode;
        private List<DateTime> _freedates;
        private bool _freetimeslots = false;

        public int CustomerId
        {
            get
            {
                return this._customerid;
            }
            set
            {
                this._customerid = value;
            }
        }

        public int TaskId
        {
            get
            {
                return this._taskid;
            }
            set
            {
                this._taskid = value;
            }
        }

        public int ExistingServiceCarScheduleDetailId
        {
            get
            {
                return this._existingservicecarscheduledetailid;
            }
            set
            {
                this._existingservicecarscheduledetailid = value;
            }
        }

        public List<DateTime> FreeDates
        {
            get
            {
                return this._freedates;
            }
            set
            {
                this._freedates = value;
            }
        }

        public int SelectedZipCode
        {
            get
            {
                return this._selectedzipcode;
            }
            set
            {
                this._selectedzipcode = value;
            }
        }

        public bool FreeTimeSlots
        {
            get
            {
                return this._freetimeslots;
            }
            set
            {
                this._freetimeslots = value;
            }
        }


        protected void Page_Load(object sender, EventArgs e)
        {
            // Initiate datalayer
            TireServiceDB db = new TireServiceDB();

            if (Page.IsPostBack != true)
            {
                // Bind data to container dropdownlist
                ddlContainer.DataSource = db.GetContainers();
                ddlContainer.ValueField = "ContainerId";
                ddlContainer.TextField = "ContainerNumber";
                ddlContainer.DataBind();

                // Select first container if no one preselected
                ddlContainer.SelectedIndex = 1;

                gvServiceDriveTasks.FocusedRowIndex = -1;

                // Reset selected service
                Session["BookingExistingServiceCarScheduleDetailId"] = null;
            }

            // Bind driving area dropdown list
            BindArea(db, Convert.ToInt32(ddlContainer.Value));

            // Get input on number of records to show
            int? RecordCount = null;
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "0")
            {
                RecordCount = 10;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "1")
            {
                RecordCount = 20;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "2")
            {
                RecordCount = 50;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "3")
            {
                RecordCount = 100;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "4")
            {
                RecordCount = null;
            }

            // Bind tasks
            BindTasks(db, Convert.ToInt32(ddlContainer.Value), RecordCount);
        }

        /// <summary>
        /// Bind dropdown list with possible areas that is covered by a specific container/warehouse
        /// </summary>
        /// <param name="db">Connection to database</param>
        /// <param name="ContainerId">Id on container</param>
        private void BindArea(TireServiceDB db, int ContainerId)
        {
            if (ContainerId != 0)
            {
                var Areas = from p in db.ContainerServiceCarCoverages
                            join y in db.ServiceCarGeographicalAreaAllocations on p.ServiceCarId equals y.ServiceCarId into py
                            from z in py.DefaultIfEmpty()
                            join v in db.ServiceGeographicalAreas on z.ServiceGeoAreaId equals v.ServiceGeoAreaId into zv
                            from x in zv.DefaultIfEmpty()
                            where p.ContainerId == ContainerId & z.ScheduleDate != null
                            group x by new
                            {
                                x.ServiceGeoAreaId,
                                x.Description
                            }
                                into grp
                                select new
                                {
                                    grp.Key.ServiceGeoAreaId,
                                    Description = grp.Key.Description
                                };


                ddlArea.DataSource = Areas.ToList();
                ddlArea.ValueField = "ServiceGeoAreaId";
                ddlArea.TextField = "Description";
                ddlArea.DataBind();
            }
        }

        /// <summary>
        /// Bind gridview with service drive tasks for selected container and area if selected
        /// </summary>
        /// <param name="db">Connection to database</param>
        /// <param name="ContainerId">Id on container</param>
        /// <param name="RecordCount">Number for how many records to show in gridview</param>
        private void BindTasks(TireServiceDB db, int ContainerId, int? RecordCount)
        {
            int[] tasktypestatus = new int[] { (int)Shared.TaskTypeStatus.ServiceDrive_Created, (int)Shared.TaskTypeStatus.ServiceDrive_Replan };

            if (ddlArea.SelectedIndex > 0)
            {
                // TODO: Make filtering on area possible (2013-03-03 - note made)
                //gvServiceDriveTasks.DataSource = db.TaskServiceDrivePlanningViews.Where(p => p.TaskTypeId == (int)Shared.TaskType.ServiceDrive & p.ContainerId == ContainerId & db.CountZipCodeInServiceGeographicalArea(Convert.ToInt32(ddlArea.Value), p.PrimaryZipCode) > 0).Where(d => tasktypestatus.Contains(d.TaskTypeStatusId)).ToList();

                var tasks = from p in db.TaskServiceDrivePlanningViews
                            join y in db.ContainerServiceCarCoverages on p.ContainerId equals y.ContainerId into py
                            from z in py.DefaultIfEmpty()
                            join v in db.ServiceCarGeographicalAreaAllocations on z.ServiceCarId equals v.ServiceCarId into zv
                            from x in zv.DefaultIfEmpty()
                            join w in db.ServiceGeographicalAreaZipCodeLists on x.ServiceGeoAreaId equals w.ServiceGeoAreaId into xw
                            from q in xw.DefaultIfEmpty()
                            where p.TaskTypeId == (int)Shared.TaskType.ServiceDrive & p.ContainerId == ContainerId & q.ServiceGeoAreaId == Convert.ToInt32(ddlArea.Value) & q.ZipCode == p.PrimaryZipCode & tasktypestatus.Contains(p.TaskTypeStatusId)
                            group p by new
                            {
                                p.TaskId,
                                p.DependentTaskId,
                                p.TaskTypeId,
                                p.TaskTypeDescription,
                                p.TaskTypeStatusId,
                                p.TaskTypeStatusDescription,
                                p.CustomerId,
                                p.CarId,
                                p.TireSetId,
                                p.Createdate,
                                p.CompletionDate,
                                p.GenerateInvoice,
                                p.PrimaryAddress,
                                p.PrimaryZipCode,
                                p.PrimaryCity,
                                p.PrimaryCountryId,
                                p.PrimaryLongitude,
                                p.PrimaryLatitude,
                                p.CommentToAddress,
                                p.SecondaryAddress,
                                p.SecondaryZipCode,
                                p.SecondaryCity,
                                p.SecondaryCountryId,
                                p.SecondaryLongitude,
                                p.SecondaryLatitude,
                                p.CommentToSecondaryAddress,
                                p.RegistrationNumber,
                                p.CarStatusId,
                                p.TireTypeId,
                                p.TireSetStatusId,
                                p.ContainerCargoRoomId,
                                p.CargoRoomNumber,
                                p.ContainerId,
                                p.ContainerNumber,
                                p.Distance,
                                p.DistanceSecondary

                            }
                                into grp
                                select new
                                {
                                    grp.Key.TaskId,
                                    grp.Key.DependentTaskId,
                                    grp.Key.TaskTypeId,
                                    grp.Key.TaskTypeDescription,
                                    grp.Key.TaskTypeStatusId,
                                    grp.Key.TaskTypeStatusDescription,
                                    grp.Key.CustomerId,
                                    grp.Key.CarId,
                                    grp.Key.TireSetId,
                                    grp.Key.Createdate,
                                    grp.Key.CompletionDate,
                                    grp.Key.GenerateInvoice,
                                    grp.Key.PrimaryAddress,
                                    grp.Key.PrimaryZipCode,
                                    grp.Key.PrimaryCity,
                                    grp.Key.PrimaryCountryId,
                                    grp.Key.PrimaryLongitude,
                                    grp.Key.PrimaryLatitude,
                                    grp.Key.CommentToAddress,
                                    grp.Key.SecondaryAddress,
                                    grp.Key.SecondaryZipCode,
                                    grp.Key.SecondaryCity,
                                    grp.Key.SecondaryCountryId,
                                    grp.Key.SecondaryLongitude,
                                    grp.Key.SecondaryLatitude,
                                    grp.Key.CommentToSecondaryAddress,
                                    grp.Key.RegistrationNumber,
                                    grp.Key.CarStatusId,
                                    grp.Key.TireTypeId,
                                    grp.Key.TireSetStatusId,
                                    grp.Key.ContainerCargoRoomId,
                                    grp.Key.CargoRoomNumber,
                                    grp.Key.ContainerId,
                                    grp.Key.ContainerNumber,
                                    grp.Key.Distance,
                                    grp.Key.DistanceSecondary
                                };

                if (RecordCount != null)
                {
                    gvServiceDriveTasks.DataSource = tasks.Take(Convert.ToInt32(RecordCount)).ToList();
                }
                else
                {
                    gvServiceDriveTasks.DataSource = tasks.ToList();
                }
            }
            else
            {
                if (RecordCount != null)
                {
                    gvServiceDriveTasks.DataSource = db.TaskServiceDrivePlanningViews.Where(p => p.TaskTypeId == (int)Shared.TaskType.ServiceDrive & p.ContainerId == ContainerId).Where(d => tasktypestatus.Contains(d.TaskTypeStatusId)).Take(Convert.ToInt32(RecordCount)).ToList();
                }
                else
                {
                    gvServiceDriveTasks.DataSource = db.TaskServiceDrivePlanningViews.Where(p => p.TaskTypeId == (int)Shared.TaskType.ServiceDrive & p.ContainerId == ContainerId).Where(d => tasktypestatus.Contains(d.TaskTypeStatusId)).ToList();
                }
            }

            gvServiceDriveTasks.DataBind();
        }

        /// <summary>
        /// Function that updates
        /// </summary>
        protected void ddlArea_Callback(object source, CallbackEventArgsBase e)
        {
            // Initiate datalayer
            TireServiceDB db = new TireServiceDB();

            BindArea(db, Convert.ToInt32(e.Parameter));
        }

        /// <summary>
        /// Postback function that updates gridview with tasks for cars that need servicedrive
        /// </summary>
        protected void gvServiceDriveTasks_CustomCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomCallbackEventArgs e)
        {
            TireServiceDB db = new TireServiceDB();

            // Get input on number of records to show
            int? RecordCount = null;
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "0")
            {
                RecordCount = 10;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "1")
            {
                RecordCount = 20;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "2")
            {
                RecordCount = 50;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "3")
            {
                RecordCount = 100;
            }
            if (ddlPageResultCount.SelectedItem.Value.ToString() == "4")
            {
                RecordCount = null;
            }

            // Show service drive tasks
            BindTasks(db, Convert.ToInt32(ddlContainer.Value), RecordCount);
        }

        protected void gvTaskDetail_DataSelect(object sender, EventArgs e)
        {
            TireServiceDB db = new TireServiceDB();
            ASPxGridView gvTaskDetail = (sender as ASPxGridView);
            gvTaskDetail.DataSource = db.GetTaskDetailsExtendedView(Convert.ToInt32((sender as ASPxGridView).GetMasterRowKeyValue()));
            //gvTaskDetail.DataBind();
        }

        /// <summary>
        /// Function that is raised from client side when servicedrive task is selected and update GUI with available addresses
        /// </summary>
        protected void callbackSelectAddressPanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Initiate datalayer
                TireServiceDB db = new TireServiceDB();

                // Get task
                Task task = db.GetTask(Convert.ToInt32(e.Parameter));

                // Bind data to select address panel
                ddlSelectAddress.Items.Clear();
                string add1 = task.PrimaryAddress + "|" + task.PrimaryZipCode + "|" + task.PrimaryCity;
                string add2 = task.SecondaryAddress + "|" + task.SecondaryZipCode + "|" + task.SecondaryCity;
                string add3 = "-- Anden adresse --";

                ddlSelectAddress.Items.Add(add1, 0);
                ddlSelectAddress.Items.Add(add2, 1);
                ddlSelectAddress.Items.Add(add3, 2);

                // Get car
                BusinessCarListView car = db.BusinessCarListViews.SingleOrDefault(p => p.CarId == Convert.ToInt32(task.CarId));

                if (car != null)
                {
                    // Update gui based on selected car
                    SelectCar(db, car, task.TaskId);
                }
                else
                {
                    throw new ArgumentException("Den valgte bil står ikke angivet til at skulle have skiftet hjul.");
                }

                // Bind zipcode list (Only DK ZipCodes)
                ddlZipCode.DataSource = db.GetCountryZipCodeLists(0);
                ddlZipCode.ValueField = "ZipCode";
                ddlZipCode.DataBind();

                if (Session["BookingExistingServiceCarScheduleDetailId"] != null)
                {
                    // Check if this needs to be reset
                    ServiceCarScheduleDetail detail = db.GetServiceCarScheduleDetail(Convert.ToInt32(Session["BookingExistingServiceCarScheduleDetailId"]));

                    if (detail.TaskId != null & detail.TaskId != task.TaskId)
                    {
                        // Reset existing booking session variable
                        Session["BookingExistingServiceCarScheduleDetailId"] = null;
                    }
                }

                db.Dispose();
            }
            catch (Exception ex)
            {
                // Error
                throw new ArgumentException(ex.Message);
            }
        }

        private void SelectCar(TireServiceDB db, BusinessCarListView car, int TaskId)
        {
            // Show details in GUI on selected car
            lblSelectedCarRegistrationNumberValue.Text = car.RegistrationNumber;
            lblSelectedCarBrandDescriptionValue.Text = car.CarBrandDescription;
            pExistingBooking.Visible = false;

            // Tirechange not yet booked/planned
            if (car.CarStatusId == (int)Shared.CarStatus.AwaitsTireChangePlanning)
            {
                // Car awaits tirechange planning (Booking)
                int[] tasktypestatus = new int[] { (int)Shared.TaskTypeStatus.ServiceDrive_Created, (int)Shared.TaskTypeStatus.ServiceDrive_Replan };

                Task task = db.GetTask(TaskId);
                if (task.DependentTaskId != null)
                {
                    Task dependenttask = db.GetTask(Convert.ToInt32(task.DependentTaskId));
                    if (dependenttask.CompletionDate == null)
                    {
                        throw new ArgumentException("Opgave kan ikke bookes, da der ligger anden opgave på bilen der skal udføres først. Opgave: " + dependenttask.TaskId.ToString());
                    }
                }


                //List<Task> tasks = db.GetTasksByCarAndTaskTypeStatus(car.CarId, tasktypestatus);

                //foreach (Task task in tasks)
                //{
                //    // Check if taskdetails contain TireChange
                //    if (db.TaskDetails.Where(p => p.TaskDetailTypeId == (int)Shared.TaskDetailType.ServiceDrive_ChangeTire & p.TaskId == task.TaskId).Count() == 1)
                //    {
                //        // Check if task is dependent on other task is done first
                //        if (task.DependentTaskId != null)
                //        {
                //            Task dependenttask = db.GetTask(Convert.ToInt32(task.DependentTaskId));
                //            if (dependenttask.CompletionDate == null)
                //            {
                //                throw new ArgumentException("Opgave kan ikke bookes, da der ligger anden opgave på bilen der skal udføres først. Opgave: " + dependenttask.TaskId.ToString());
                //            }
                //        }
                //    }
                //}
            }

            // Tirechange already booked / planned
            if (car.CarStatusId == (int)Shared.CarStatus.PlannedTireChange)
            {
                // Task was found
                ServiceCarScheduleDetail detail = db.GetServiceCarScheduleDetailByTaskId(TaskId);

                if (detail == null)
                {
                    throw new ArgumentException("Hjulskift står som planlagt, men service kørsel kan ikke finder - kontakt administration.");
                }
                else
                {
                    // Set page propertie
                    this.ExistingServiceCarScheduleDetailId = detail.ServiceCarScheduleDetailId;
                    Session["BookingExistingServiceCarScheduleDetailId"] = detail.ServiceCarScheduleDetailId;

                    // Show already planned date in GUI
                    pExistingBooking.Visible = true;

                    lblExistingBookingAddressValue.Text = detail.ToAddress + ", " + detail.ToZipCode + " " + detail.ToCity;
                    lblExistingBookingDateValue.Text = detail.ScheduleDate.ToShortDateString();
                    lblExistingBookingTimeslotValue.Text = string.Format("{0:t}", detail.StartTime) + " - " + string.Format("{0:t}", detail.EndTime);
                }
            }

            // This scenario will never occure, due to filter
            if (car.CarStatusId != (int)Shared.CarStatus.AwaitsTireChangePlanning & car.CarStatusId != (int)Shared.CarStatus.PlannedTireChange)
            {
                // Car status is not correct for tirechange booking
                throw new ArgumentException("Ingen bil står angivet til at skulle have skiftet hjul. Venligst kontakt vores kundesupport hvis der er sket en fejl.");
            }
        }

        /// <summary>
        /// Function that is raised from client side and update GUI with available dates based on selected address/zipcode
        /// </summary>
        protected void callbackSelectDatePanel_Callback(object source, DevExpress.Web.ASPxClasses.CallbackEventArgsBase e)
        {
            try
            {
                // Instantiate data layer
                TireServiceDB db = new TireServiceDB();

                // Get values (0: SelectedAddress (0: Primary, 1: Secondary, 2: New one), 1: ZipCode, 2: True/false - show all timeslots)
                string[] param = e.Parameter.Split('|');

                int SelectedAddress = Convert.ToInt32(param[0]);
                string ZipCode = param[1].ToString();
                bool ShowAllTimeslots = Convert.ToBoolean(param[2]);

                if (ShowAllTimeslots)
                {
                    // Get service cars that services that selected container/warehouse
                    int[] ServiceCarId = db.GetContainerServiceCars(Convert.ToInt32(ddlContainer.Value));

                    var AvailableDates = from p in db.ServiceCarScheduleDetailViews
                                         where p.ScheduleDate >= DateTime.Now & p.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available & ServiceCarId.Contains(p.ServiceCarId)
                                         select new
                                         {
                                             p.ScheduleDate
                                         };
                    
                    if (AvailableDates.Count() == 0)
                    {
                        throw new ArgumentException("Ingen ledige tider kunne findes. Opret mere kapacitet.");
                    }
                    else
                    {
                        // Clear free dates if contain old values
                        if (this.FreeDates != null)
                        {
                            this.FreeDates.Clear();
                        }

                        List<DateTime> dates = new List<DateTime>();

                        foreach (var date in AvailableDates.Distinct().ToList())
                        {
                            dates.Add(date.ScheduleDate);
                        }

                        this.FreeDates = dates;

                        ddlSelectDate.DataSource = dates;
                        ddlSelectDate.DataBind();
                    }
                }
                else
                {
                    // Get dates where we will be driving in zipcode area and where theres i free capacity in the future
                    var AvailableDatesOnZipCode = from p in db.ServiceGeographicalAreaZipCodeLists
                                                  join y in db.ServiceCarGeographicalAreaAllocations on p.ServiceGeoAreaId equals y.ServiceGeoAreaId into py
                                                  from z in py.DefaultIfEmpty()
                                                  join v in db.ServiceCarSchedules on
                                                  new { Col1 = z.ServiceCarId, Col2 = z.ScheduleDate }
                                                  equals
                                                  new { Col1 = v.ServiceCarId, Col2 = v.ScheduleDate }
                                                  into pv
                                                  from x in pv.DefaultIfEmpty()
                                                  // Filter parameters: ZipCode, Date, None GroupServiceDay, Available capacity
                                                  where p.ZipCode == ZipCode & z.ScheduleDate >= DateTime.Now & x.GroupServiceCarScheduleId == null & db.ServiceCarScheduleDetails.Where(q => q.ServiceCarId == z.ServiceCarId & q.ScheduleDate == z.ScheduleDate & q.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available).Count() > 0
                                                  select new
                                                  {
                                                      z.ScheduleDate
                                                  };

                    if (AvailableDatesOnZipCode.Count() == 0)
                    {
                        throw new ArgumentException("Ingen ledige tider kunne findes. Venligst kontakt vores kundesupport for en tid.");
                    }
                    else
                    {
                        // Clear free dates if contain old values
                        if (this.FreeDates != null)
                        {
                            this.FreeDates.Clear();
                        }

                        List<DateTime> dates = new List<DateTime>();

                        foreach (var date in AvailableDatesOnZipCode.Distinct().ToList())
                        {
                            dates.Add(date.ScheduleDate);
                        }

                        this.FreeDates = dates;

                        ddlSelectDate.DataSource = dates;
                        ddlSelectDate.DataBind();
                    }
                }

                db.Dispose();
            }
            catch (Exception ex)
            {

                // Error
                //throw new ArgumentException(ex.Message);
            }
        }

        /// <summary>
        /// Postback function that updates overview of capacity on specific service car and date
        /// </summary>
        protected void gvFreeCapacity_CustomCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomCallbackEventArgs e)
        {
            // Get values (0: ScheduleDate, 1: True/false - allow outside service area booking)
            string[] param = e.Parameters.Split('|');

            DateTime ScheduleDate = Convert.ToDateTime(param[0]);
            bool AllowOutsideArea = Convert.ToBoolean(param[1]);

            // Instantiate data layer
            TireServiceDB db = new TireServiceDB();

            // Get service cars that services that selected container/warehouse
            int[] ServiceCarId = db.GetContainerServiceCars(Convert.ToInt32(ddlContainer.Value));

            // TODO: 01-06-2013: Overvej bedre synliggørelse af område og gruppebooking tildeling (ligesom i gamle planlægning)
            if (AllowOutsideArea)
            {                
                gvFreeCapacity.DataSource = db.ServiceCarScheduleDetailViews.Where(p => p.ScheduleDate == ScheduleDate).Where(d => ServiceCarId.Contains(d.ServiceCarId)).OrderBy(d => d.StartTime).ToList();
                gvFreeCapacity.DataBind();
            }
            else
            {
                // Show timeslots that are only within the service drive area
                var Timeslots = from p in db.ServiceCarScheduleDetailViews
                                join v in db.ServiceCarSchedules on
                                new { Col1 = p.ServiceCarId, Col2 = p.ScheduleDate }
                                equals
                                new { Col1 = v.ServiceCarId, Col2 = v.ScheduleDate }
                                into pv
                                from x in pv.DefaultIfEmpty()

                                join y in db.ServiceCarGeographicalAreaAllocations on
                                new { Col1 = x.ServiceCarId, Col2 = x.ScheduleDate }
                                equals
                                new { Col1 = y.ServiceCarId, Col2 = y.ScheduleDate }
                                into xy
                                from w in xy.DefaultIfEmpty()

                                join a in db.ServiceGeographicalAreaZipCodeLists on w.ServiceGeoAreaId equals a.ServiceGeoAreaId
                                into wa
                                from b in wa.DefaultIfEmpty()
                                // Filter parameters: ZipCode, Date, None GroupServiceDay, Available capacity
                                where b.ZipCode == ddlZipCode.Value.ToString() & p.ScheduleDate == ScheduleDate & x.GroupServiceCarScheduleId == null & p.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available
                                select p;
            }

            // Group view on servicecar
            gvFreeCapacity.GroupSummary.Clear();
            gvFreeCapacity.GroupBy(gvFreeCapacity.Columns["ServiceCarId"]);
            gvFreeCapacity.ExpandAll();

            db.Dispose();
        }

        /// <summary>
        /// Gridview function that runs when databinding - Changes colors based on customerconfirmed value
        /// </summary>
        protected void gvFreeCapacity_HtmlRowPrepared(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewTableRowEventArgs e)
        {
            if (e.RowType != DevExpress.Web.ASPxGridView.GridViewRowType.Data) return;

            int servicetype = Convert.ToInt32(gvFreeCapacity.GetRowValuesByKeyValue(e.KeyValue, "ScheduleDetailTypeId"));

            if (servicetype == (int)Shared.ScheduleDetailType.Available)
            {
                e.Row.BackColor = System.Drawing.Color.White;
            }
            if (servicetype == (int)Shared.ScheduleDetailType.Blocked)
            {
                e.Row.BackColor = System.Drawing.Color.Red;
            }
            if (servicetype == (int)Shared.ScheduleDetailType.ServiceDrive)
            {
                // Get customerconfirmed value - based on that rows will be formated
                bool CustomerConfirmed = Convert.ToBoolean(gvFreeCapacity.GetRowValuesByKeyValue(e.KeyValue, "CustomerConfirmed"));

                if (CustomerConfirmed)
                {
                    e.Row.BackColor = System.Drawing.Color.DarkGreen;
                }
                else
                {
                    e.Row.BackColor = System.Drawing.Color.Orange;
                }
            }
        }

        /// <summary>
        /// Postback function that updates overview of other cars that need service near a specific area/address
        /// </summary>
        protected void gvNearByServiceDriveTasks_CustomCallback(object sender, DevExpress.Web.ASPxGridView.ASPxGridViewCustomCallbackEventArgs e)
        {
            // Get values (0: Selected address, 1: ZipCode)
            string[] param = e.Parameters.Split('|');

            string Address = param[0].ToString();
            int ZipCode = Convert.ToInt32(param[1]);

            // Instantiate data layer
            TireServiceDB db = new TireServiceDB();

            // TODO: Make code

            //gvNearByServiceDriveTasks.DataSource = 
            //gvNearByServiceDriveTasks.DataBind();
        }

        /// <summary>
        /// Callback function that bookes selected servicedrive task into selected servicedetail
        /// </summary>
        protected void callBookService_Callback(object sender, CallbackEventArgs e)
        {
            //TODO: Old input // Get input parameters from client (0: taskid, 1: servicescheduledetailid, 2: usesecondaryaddress - true/false, 3: customerconfirmed - true/false, 4: note, 5: allow booking outside area - true/false (optional))
            // Get input parameters from client (0: taskid, 1: servicescheduledetailid, 2: address, 3: zipcode, 4: allow booking outside area - true/false (optional))
            string[] param = e.Parameter.Split('|');

            int TaskId = Convert.ToInt32(param[0]);
            int ServiceCarScheduleDetailId = Convert.ToInt32(param[1]);
            string Address = param[2].ToString();
            string ZipCode = param[3].ToString();
            bool AllowAllocationOutSideArea = Convert.ToBoolean(param[4]);

            TireServiceDB db = new TireServiceDB();

            Task task = db.GetTask(TaskId);
            if (task == null)
            {
                throw new ArgumentException("Ingen servicekørsel valgt - venligst vælg servicekørsel først.");
            }

            // Other validation of Task
            if (task.TaskTypeStatusId == (int)Shared.TaskTypeStatus.ServiceDrive_Cancelled)
            {
                throw new ArgumentException("Service kørsel er annulleret og kan derfor ikke planlægges ind.");
            }
            if (Convert.ToInt32(Session["BookingExistingServiceCarScheduleDetailId"]) == 0) 
            {   
                if (task.TaskTypeStatusId == (int)Shared.TaskTypeStatus.ServiceDrive_Planned)
                {
                    throw new ArgumentException("Service kørsel er allerede planlagt.");
                }
            }
            if (task.TaskTypeStatusId == (int)Shared.TaskTypeStatus.ServiceDrive_Completed)
            {
                throw new ArgumentException("Service kørsel er gennemført/afsluttet og kan derfor ikke planlægges ind.");
            }
            
            // Check if user has selected car from carneedservice gridview
            Car car = db.GetCar(Convert.ToInt32(task.CarId));
            if (car == null)
            {
                throw new ArgumentException("Ingen bil valgt angivet på servicekørsel - booking kan derfor ikke gennemføres.");
            }

            // Get servicecarscheduledetail record
            ServiceCarScheduleDetail scheduledetail = db.GetServiceCarScheduleDetail(ServiceCarScheduleDetailId);
            if (scheduledetail == null)
            {
                throw new ArgumentException("Valgt tidsrum eksistere ikke - venligst prøv igen.");
            }

            // Check if timeslot is "available"
            if (scheduledetail.ScheduleDetailTypeId != (int)Shared.ScheduleDetailType.Available)
            {
                throw new ArgumentException("Valgt tidsrum ikke ledigt - venligst vælg et andet.");
            }

            // Check if area validation is needed
            ServiceCarGeographicalAreaAllocation areaallocation = db.GetServiceCarGeographicalAreaAllocation(scheduledetail.ServiceCarId, scheduledetail.ScheduleDate);
            if (areaallocation != null)
            {
                if (!AllowAllocationOutSideArea)
                {
                    if (db.ServiceGeographicalAreaZipCodeLists.Where(p => p.ServiceGeoAreaId == areaallocation.ServiceGeoAreaId & p.ZipCode == ZipCode).Count() == 0)
                    {
                        throw new ArgumentException("Adressen ligger ikke i kørselsområdet - venligst vælg en anden dag eller angiv at allokering udenfor område er tilladt.");
                    }
                }
            }

            ServiceCarScheduleDetail existingdetail = new ServiceCarScheduleDetail();

            // Check if booking already exists and is selected
            if (Convert.ToInt32(Session["BookingExistingServiceCarScheduleDetailId"]) != 0) 
            {
                // Get existing booking
                existingdetail = db.GetServiceCarScheduleDetail(Convert.ToInt32(Session["BookingExistingServiceCarScheduleDetailId"]));

                // Update timeslot - reset to available status
                ServiceCarScheduleDetailBLL detailBLL = new ServiceCarScheduleDetailBLL();
                detailBLL.MakeServiceCarScheduleDetailAvailable(db, existingdetail, true);
            }

            string City = db.CountryZipCodeLists.SingleOrDefault(p => p.ZipCode == ZipCode).City;

            Customer customer = db.GetCustomer(Convert.ToInt32(task.CustomerId));

            // Insert car on timeslot and update scheduledetail
            scheduledetail.CarId = car.CarId;
            scheduledetail.ToTireSetId = task.TireSetId;
            scheduledetail.CustomerConfirmed = false;
            scheduledetail.ToAddress = Address;
            scheduledetail.ToZipCode = ZipCode;
            scheduledetail.ToCity = City;
            scheduledetail.ToCountryId = customer.CountryId;
            if (Address != "" & ZipCode != "" & City != "")
            {
                // Calculate longitude and latitude for secondary address
                try
                {
                    string secondaryAddress = Address + ", " + ZipCode + " " + City + ", " + db.GetCountryName(customer.CountryId);
                    GoogleMaps googleMapAPI = new GoogleMaps(Convert.ToString(ConfigurationManager.AppSettings["MapKey"]));
                    double[] LongLatSecondary = googleMapAPI.GetLongLatCoordinates(secondaryAddress);
                    scheduledetail.ToLongitude = LongLatSecondary[0];
                    scheduledetail.ToLatitude = LongLatSecondary[1];
                }
                catch (Exception)
                {
                    // Error calculating longitude and latitude - values will be set to null
                }

            }
            else
            {
                scheduledetail.ToLongitude = null;
                scheduledetail.ToLatitude = null;
            }            

            //scheduledetail.Note = Note;
            scheduledetail.ScheduleDetailTypeId = (int)Shared.ScheduleDetailType.ServiceDrive;

            // Fetch all TaskDetails to see if Task contain TireChange
            List<TaskDetail> taskdetails = db.GetTaskDetails(task.TaskId);

            foreach (TaskDetail taskdetail in taskdetails)
            {
                if (taskdetail.TaskDetailTypeId == (int)Shared.TaskDetailType.ServiceDrive_ChangeTire)
                {
                    // Update car with new status        
                    car.CarStatusId = (int)Shared.CarStatus.PlannedTireChange;
                }
            }

            // Relate Task to ServiceCarScheduleDetail
            scheduledetail.TaskId = task.TaskId;

            // Update Task status
            task.TaskTypeStatusId = (int)Shared.TaskTypeStatus.ServiceDrive_Planned;

            // Update property
            this.ExistingServiceCarScheduleDetailId = scheduledetail.ServiceCarScheduleDetailId;
            Session["BookingExistingServiceCarScheduleDetailId"] = scheduledetail.ServiceCarScheduleDetailId;

            // Submit changes to database
            db.SubmitChanges();

            // Dispose database connection
            db.Dispose();
        }

        /// <summary>
        /// Callback function that deletes bookes servicedetail
        /// </summary>
        protected void callDeleteBookedService_Callback(object sender, CallbackEventArgs e)
        {
            // Get input parameters from client (servicescheduledetailid)
            string[] param = e.Parameter.Split('|');

            int ServiceCarScheduleDetailId = Convert.ToInt32(param[0]);

            TireServiceDB db = new TireServiceDB();
            
            // Get servicecarscheduledetail record
            ServiceCarScheduleDetail scheduledetail = db.GetServiceCarScheduleDetail(ServiceCarScheduleDetailId);
            if (scheduledetail == null)
            {
                throw new ArgumentException("Valgt tidsrum eksistere ikke - venligst prøv igen.");
            }

            // Check if timeslot is booked or blocked
            if (scheduledetail.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available)
            {
                throw new ArgumentException("Valgt tidsrum er ikke booket - venligst vælg et andet.");
            }

            if (scheduledetail.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.ServiceDrive)
            {
                // Get related task
                Task task = db.GetTask(Convert.ToInt32(scheduledetail.TaskId));

                // Change status on task
                task.TaskTypeStatusId = (int)Shared.TaskTypeStatus.ServiceDrive_Replan;

                // Fetch all TaskDetails to see if Task contain TireChange
                List<TaskDetail> taskdetails = db.GetTaskDetails(task.TaskId);

                foreach (TaskDetail taskdetail in taskdetails)
                {
                    if (taskdetail.TaskDetailTypeId == (int)Shared.TaskDetailType.ServiceDrive_ChangeTire)
                    {
                        Car car = db.GetCar(Convert.ToInt32(task.CarId));

                        // Update car with new status        
                        car.CarStatusId = (int)Shared.CarStatus.AwaitsTireChangePlanning;
                    }
                }
            }

            // Reset session variable if service task that is selected is same as the one being deleted
            if (scheduledetail.ServiceCarScheduleDetailId == Convert.ToInt32(Session["BookingExistingServiceCarScheduleDetailId"]))
            {
                Session["BookingExistingServiceCarScheduleDetailId"] = null;
            }
            
            // Return taskid to client to update UI if task is selected to update
            e.Result = scheduledetail.TaskId.ToString();

            // Update timeslot - reset to available status
            ServiceCarScheduleDetailBLL detailBLL = new ServiceCarScheduleDetailBLL();
            detailBLL.MakeServiceCarScheduleDetailAvailable(db, scheduledetail, true);

            // Commit changes to database
            db.SubmitChanges();

            // Dispose database connection
            db.Dispose();
        }

        /// <summary>
        /// Callback function that handles approval and blocking of dayplan records
        /// </summary>
        protected void callBackManageCustomerApproval_Callback(object sender, CallbackEventArgs e)
        {
            // Get values (0: Actionparameter, 1-X: Array of servicecarscheduledetailid's)
            string[] param = e.Parameter.Split(',');

            // Instantiate database
            TireServiceDB db = new TireServiceDB();

            // Validate action to take
            if (Convert.ToString(param[0]) == "RequestApproval")
            {
                for (int i = 1; i < param.Length; i++)
                {
                    //SendConfirmationEmailToSelected(db, Convert.ToInt32(param[i]));
                }
            }
            if (Convert.ToString(param[0]) == "CustomerApproved")
            {
                for (int i = 1; i < param.Length; i++)
                {
                    //CustomerApproved(db, Convert.ToInt32(param[i]), true);
                }
            }
            if (Convert.ToString(param[0]) == "RemoveApprovalOnSelected")
            {
                for (int i = 1; i < param.Length; i++)
                {
                    //CustomerApproved(db, Convert.ToInt32(param[i]), false);
                }
            }
            if (Convert.ToString(param[0]) == "AddBlockOnSelected")
            {
                for (int i = 1; i < param.Length; i++)
                {
                    ServiceCarScheduleDetail detail = db.GetServiceCarScheduleDetail(Convert.ToInt32(param[i]));

                    if (detail.ScheduleDetailTypeId == (int)Shared.ScheduleDetailType.Available)
                    {
                        detail.ScheduleDetailTypeId = (int)Shared.ScheduleDetailType.Blocked;
                        detail.Note = "Tidsrum blokeret";
                    }
                }
            }

            // Commit changes to database
            db.SubmitChanges();

            // Dispose database connection
            db.Dispose();
        }
    }
}